package com.maimao.upload.service;

import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.fdfs.ThumbImageConfig;
import com.github.tobato.fastdfs.domain.upload.FastFile;
import com.github.tobato.fastdfs.domain.upload.FastImageFile;
import com.github.tobato.fastdfs.exception.FdfsServerException;
import com.github.tobato.fastdfs.exception.FdfsUnsupportStorePathException;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.maimao.core.constant.Constants;
import com.maimao.core.enums.ExceptionEnum;
import com.maimao.core.enums.SizeUnit;
import com.maimao.core.exception.MaiMaoException;
import com.maimao.core.model.resp.Result;
import com.maimao.core.utils.MapUtils;
import com.maimao.upload.client.BrandClient;
import com.maimao.upload.client.UserClient;
import com.maimao.upload.config.properties.UploadProperties;
import com.maimao.upload.utils.UploadCache;
import com.maimao.upload.utils.UploadUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ExecutionException;

/**
 * @author MaoLin Wang
 * @date 2020/12/10 4:43 下午
 */
@Slf4j
@Service
public class UploadService {
    protected Logger logger = LoggerFactory.getLogger(UploadService.class);

    /**
     * 批量删除
     *
     * @param urls
     */
    public void deleteBatch(List<String> urls) {
        for (String url : urls) {
            deleteFile(url);
        }
        log.info("delete file：{}", urls);
    }

    /**
     * @param file
     * @param limit 限制大小 MB
     * @return
     */
    public String uploadCommon(MultipartFile file, Integer limit, boolean isImage) {
        String originalFileName = file.getOriginalFilename();
        try {
            if (!UploadUtils.checkFileSize(file.getSize(), limit, SizeUnit.MB)) {
                return null;
            }
            //校验文件类型
            checkFile(file, originalFileName, isImage);

            //获取拓展名
            String extension = UploadUtils.getExtension(file.getOriginalFilename(), ".");

            StorePath storePath;
            if (isImage) {
                //校验文件内容
                BufferedImage image = ImageIO.read(file.getInputStream());
                if (image == null) {
                    throw new MaiMaoException(ExceptionEnum.INVALID_FILE_TYPE);
                }
                //上传到FastDFS
                storePath = uploadImage(file, extension);
            } else {
                storePath = uploadFile(file, extension);
            }
            String logoUrl = uploadProperties.getBaseUrl() + storePath.getFullPath();
            //返回路径
            return logoUrl;
        } catch (IOException e) {
            //上传失败
            logger.error("[文件上传]上传文件失败!", e);
            throw new MaiMaoException(ExceptionEnum.UPLOAD_ERROR);
        }

    }


    public String uploadStream(InputStream inputStream, Integer limit, String extension) {
        try {
            if (!UploadUtils.checkFileSize(Long.valueOf(inputStream.available()), limit, SizeUnit.MB)) {
                return null;
            }
            StorePath storePath;
            storePath = uploadStream(inputStream, extension);
            String url = uploadProperties.getBaseUrl() + storePath.getFullPath();
            //返回路径
            return url;
        } catch (IOException e) {
            //上传失败
            logger.error("[流文件上传]上传文件失败!", e);
            throw new MaiMaoException(ExceptionEnum.UPLOAD_ERROR);
        }

    }


    /**
     * service 后台上传品牌
     */
    public String uploadBrand(MultipartFile file, Integer brandId) {

        String originalFileName = file.getOriginalFilename();
        try {
            //校验文件类型
            checkFile(file, originalFileName, true);
            //校验文件内容
            BufferedImage image = ImageIO.read(file.getInputStream());
            if (image == null) {
                throw new MaiMaoException(ExceptionEnum.INVALID_FILE_TYPE);
            }
            /**
             * 先删除原来的logo
             */
            //获取拓展名
            String extension = UploadUtils.getExtension(file.getOriginalFilename(), ".");
            deleteOldLogo(brandId);

            //上传到FastDFS
            StorePath storePath = uploadImage(file, extension);

            String logoUrl = uploadProperties.getBaseUrl() + storePath.getFullPath();
            //修改logo地址
            Map<String, String> updateParams = new HashMap<>(MapUtils.initCapacity(2));
            updateParams.put(Constants.ID, brandId + "");
            updateParams.put("logo", logoUrl);

            brandClient.updateLogo(updateParams);

            //返回路径
            return logoUrl;
        } catch (IOException e) {
            //上传失败
            logger.error("[文件上传]上传文件失败!", e);
            throw new MaiMaoException(ExceptionEnum.UPLOAD_ERROR);
        }

    }

    /**
     * 上传会员的证件照 （没必要单独弄个上传证件照的方法，一开始考虑不周）
     */
    public String uploadMemberIdCard(MultipartFile file, String type, Long userId) {

        String originalFileName = file.getOriginalFilename();
        try {
            //校验文件类型
            checkFile(file, originalFileName, true);
            //校验文件内容
            BufferedImage image = ImageIO.read(file.getInputStream());
            if (image == null) {
                throw new MaiMaoException(ExceptionEnum.INVALID_FILE_TYPE);
            }

            //获取拓展名
            String extension = UploadUtils.getExtension(file.getOriginalFilename(), ".");
            deleteOldIdCard(userId, type);

            //上传到FastDFS
            StorePath storePath = uploadWithThumb(file, extension);

            //缩略图地址
            String idCardUrl = uploadProperties.getBaseUrl() + thumbImageConfig.getThumbImagePath(storePath.getFullPath());


            Map<String, String> updateParams = new HashMap<>(MapUtils.initCapacity(2));
            updateParams.put(Constants.ID, userId + "");
            updateParams.put(type, idCardUrl);

            userClient.updateIdCard(updateParams);

            //更新缓存
            uploadCache.refreshCache(userId);
            uploadCache.print(userId);

            //返回路径
            return idCardUrl;
        } catch (IOException e) {
            //上传失败
            logger.error("[文件上传]上传会员证件失败!", e);
            throw new MaiMaoException(ExceptionEnum.UPLOAD_ERROR);
        }

    }


    /**
     * 删除旧的证件地址
     */
    private void deleteOldIdCard(Long userId, String type) {
        Optional<Map<String, String>> optionalMap = null;
        try {
            optionalMap = uploadCache.getMemberIdUrl().get(userId);
        } catch (ExecutionException e) {
            e.printStackTrace();
            log.error("get cache: memberIdUrl error {}", e.getMessage());
        }
        if (optionalMap == null) {
            //非法id
            throw new MaiMaoException(ExceptionEnum.ILLEGAL_USER);
        }
        String targetOldUrl = optionalMap.get().get(type);
        String fullPath = UploadUtils.getFullPathFromThumb(targetOldUrl);
        deleteFile(fullPath);
        deleteFile(targetOldUrl);


    }

    /**
     * 上传图片
     */
    private StorePath uploadImage(MultipartFile file, String extension) throws IOException {

        return storageClient.uploadImage(new FastImageFile.Builder()
                .withFile(
                        file.getInputStream(),
                        file.getSize(),
                        extension).
                        build());
    }

    /**
     * 流上传
     */
    private StorePath uploadStream(InputStream inputStream, String extension) throws IOException {

        return storageClient.uploadFile(new FastImageFile.Builder()
                .withFile(
                        inputStream,
                        inputStream.available(),
                        extension).
                        build());
    }

    /**
     * 上传文件
     */
    private StorePath uploadFile(MultipartFile file, String extension) throws IOException {


        return storageClient.uploadFile(new FastFile.Builder()
                .withFile(
                        file.getInputStream(),
                        file.getSize(),
                        extension).
                        build());
    }

    private StorePath uploadWithThumb(MultipartFile file, String extension) throws IOException {
        return storageClient.uploadImageAndCrtThumbImage(file.getInputStream(), file.getSize(), extension, null);
    }

    /**
     * 删除旧品牌Logo
     *
     * @param brandId 品牌id
     */
    private void deleteOldLogo(Integer brandId) {

        Result<String> result = brandClient.findLogoById(brandId);
        if (result != null) {
            String oldLogo = result.getData();
            if (!StringUtils.isEmpty(oldLogo)) {
                try {
                    storageClient.deleteFile(oldLogo);
                } catch (FdfsUnsupportStorePathException e) {
                    logger.warn("target url {} is not store in FastDFS", oldLogo);
                }
            }

        }
    }

    private void checkFile(MultipartFile file, String originalFileName, boolean image) {
        String contentType = file.getContentType();

        if (image ? (!IMAGE_ALLOW_TYPES.contains(contentType)) : (!FILE_ALLOW_TYPES.contains(contentType))) {
            logger.info("文件内容不合法:{}", originalFileName);
            throw new MaiMaoException(ExceptionEnum.INVALID_FILE_TYPE);
        }
    }


    /**
     * 根据旧地址(非缩略图)获取缩略图地址并删除缩略图
     *
     * @param oldUrl 旧地址 （FullPath）
     */
    private void delThumbImage(String oldUrl) {
        String thumbName = UploadUtils.getThumbUrlFromFullPath(oldUrl, width, height);
        deleteFile(thumbName);
    }

    private void deleteFile(String url) {
        try {
            if (!StringUtils.isEmpty(url)) {
                storageClient.deleteFile(url);
            }
        } catch (FdfsServerException e) {
            logger.error("文件不存在:{}", url);
        } catch (FdfsUnsupportStorePathException e) {
            logger.warn("target url {} is not store in FastDFS", url);
        }
    }

    /**
     * 缩略图宽
     */
    @Value("${fdfs.thumb-image.width}")
    private Integer width;

    /**
     * 缩略图高
     */
    @Value("${fdfs.thumb-image.height}")
    private Integer height;


    /**
     * yml中的配置信息
     */
    @Autowired
    private UploadProperties uploadProperties;

    @Autowired
    private UploadCache uploadCache;

    /**
     * 获取缩略图
     */
    @Autowired
    private ThumbImageConfig thumbImageConfig;


    @Autowired
    private BrandClient brandClient;
    @Autowired
    private UserClient userClient;

    @Autowired
    private FastFileStorageClient storageClient;

    private static final List<String> IMAGE_ALLOW_TYPES = Arrays.asList("image/jpg", "image/jpeg", "image/jpg", "image/png", "image/bmp");
    private static final List<String> FILE_ALLOW_TYPES = Arrays.asList("application/vnd.ms-excel");


}
